package com.aiatomic.countlib;

import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import android.util.Base64;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.dyve.counting.CountingManager;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

public class CountService extends Service implements Runnable {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "Count");
            startForeground(1, builder.build());
        }
        if (intent != null) {
            new Thread(this).start();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(5679, 50, InetAddress.getLocalHost());
            while (true) {
                Socket accept = serverSocket.accept();
                async(accept);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void async(final Socket accept) {
        new Thread() {
            @Override
            public void run() {
                InputStream inputStream = null;
                OutputStream outputStream = null;
                try {
                    inputStream = accept.getInputStream();
                    String read = read(inputStream);
                    Log.e("LIB", "Read Over " + read);
                    Bean bean = getBean(read);
                    if (bean == null) {
                        outputStream = accept.getOutputStream();
                        Result result = new Result();
                        result.count = 0;
                        result.lastError = "请求参数有误";
                        result.success = false;
                        sendData(outputStream, new Gson().toJson(result));
                    } else {
                        Bitmap b1 = getBitmap(bean.img);
                        Result result = new Result();
                        if (b1 == null) {
                            result.count = 0;
                            result.lastError = "bitmap empty!";
                        } else {
                            result.count = CountingManager.count(b1, null, bean.type, path(bean.config));
                            result.lastError = CountingManager.getLastError();
                        }
                        result.success = true;
                        if (result.count > 0) {
                            final int[] paramArrayOfInt1 = new int[result.count];
                            final int[] paramArrayOfInt2 = new int[result.count];
                            final int[] paramArrayOfInt3 = new int[result.count];
                            final int[] paramArrayOfInt4 = new int[result.count];
                            final int[] paramArrayOfInt5 = new int[result.count];
                            CountingManager.getResults(paramArrayOfInt1, paramArrayOfInt2, paramArrayOfInt3, paramArrayOfInt4, paramArrayOfInt5);
                            result.paramArrayOfInt1 = paramArrayOfInt1;
                            result.paramArrayOfInt2 = paramArrayOfInt2;
                            result.paramArrayOfInt3 = paramArrayOfInt3;
                            result.paramArrayOfInt4 = paramArrayOfInt4;
                            result.paramArrayOfInt5 = paramArrayOfInt5;
                        }
                        outputStream = accept.getOutputStream();
                        sendData(outputStream, new Gson().toJson(result));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                        if (outputStream != null) {
                            outputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    private String path(String config) {
        //"/storage/emulated/0/Android/data/com.aiatomic.couting/files/tpl_2006_1001/t_NewBars_Small_011.dv2"
        return new File(getExternalCacheDir(), config.substring(config.lastIndexOf("/") + 1)).getAbsolutePath();
    }

    public Bean getBean(String s) {
        try {
            JSONObject jo = new JSONObject(s);
            Bean bean = new Bean();
            bean.img = jo.getString("img");
            bean.type = jo.getInt("type");
            bean.config = jo.getString("config");
            return bean;
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String read(InputStream inputStream) {
        try {
            byte[] lengthBytes = read(inputStream, 4);
            int len = byte2Int(lengthBytes);
            try {
                byte[] bytesBody = read(inputStream, len);
                String body = new String(bytesBody, StandardCharsets.UTF_8);
                return body.trim();
            } catch (OutOfMemoryError | NegativeArraySizeException error) {
                error.printStackTrace();
                return "";
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    private Bitmap getBitmap(String base64) {
        byte[] bytes = Base64.decode(base64, Base64.DEFAULT);
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    }

    private byte[] read(InputStream is, int len) throws IOException {
        byte[] bytes = new byte[len];
        int offset = 0;
        int readLen = len;
        int realReadLen = 0;
        while (realReadLen < len) {
            if (is == null) {
                break;
            }
            int currentRead = is.read(bytes, offset, readLen);
            if (currentRead != -1) {
                realReadLen += currentRead;
                offset = realReadLen;
                readLen = len - offset;
            } else {
                break;
            }
        }
        return bytes;
    }

    public int byte2Int(byte[] b) {
        int intValue = 0;
        for (int i = 0; i < b.length; i++) {
            intValue += (b[i] & 0xFF) << (8 * (3 - i));
        }
        return intValue;
    }

    private void sendData(OutputStream outputStream, String data) {
        synchronized (this) {
            byte[] body = null;
            body = data.getBytes(StandardCharsets.UTF_8);
            if (body == null) {
                return;
            }

            int length = 4 + body.length;
            ByteBuffer buffer = ByteBuffer.allocate(length);
            buffer.order();
            buffer.putInt(body.length);
            buffer.put(body);
            try {
                if (outputStream != null) {
                    outputStream.write(buffer.array());
                    outputStream.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
